package com.g.localmsg.starter.aspect;

import com.alibaba.fastjson2.JSON;
import com.g.localmsg.starter.annotation.LocalTransaction;
import com.g.localmsg.starter.model.InvokeCtx;
import com.g.localmsg.starter.model.TaskState;
import com.g.localmsg.starter.model.TransactionMsgDO;
import com.g.localmsg.starter.service.TransactionService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Aspect
@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class DistributedTransactionAspect {

    private static final Logger log = LoggerFactory.getLogger(DistributedTransactionAspect.class);

    @Autowired
    private TransactionService transactionService;

    @Around("@annotation(com.g.localmsg.starter.annotation.LocalTransaction)")
    public Object doTransaction(ProceedingJoinPoint joinPoint) {
        log.debug("DistributedTransactionAspect: 分布式事务调用拦截 -> {}", joinPoint.getSignature().toShortString());
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        //获取注解信息
        Method method = signature.getMethod();
        LocalTransaction txAnnotation = method.getAnnotation(LocalTransaction.class);
        if (txAnnotation == null) {
            return null;
        }
        //封装方法调用上下文
        List<String> parameterTypeList = Arrays.stream(method.getParameterTypes()).map(Class::getName).collect(Collectors.toList());
        InvokeCtx invokeCtx = InvokeCtx.builder()
                .methodName(method.getName())
                .className(method.getDeclaringClass().getName())
                .parameterTypes(parameterTypeList.toArray(new String[0]))
                .args(joinPoint.getArgs())
                .timeout(txAnnotation.timeout()).build();
        //封装方法调用信息，存入数据库
        TransactionMsgDO transactionMsgDO = TransactionMsgDO.builder()
                .maxRetryCount(txAnnotation.maxRetries()).retryCount(0)
                .retryInterval(txAnnotation.interval()).nextRetryTime(LocalDateTime.now().plusSeconds(txAnnotation.interval()))
                .state(TaskState.PENDING.getCode()).priority(txAnnotation.priority())
                .invokeCtx(JSON.toJSONString(invokeCtx)).build();
        //调用分布式事务服务
        transactionService.executeDisTransaction(transactionMsgDO, txAnnotation.async());
        return null;
    }
}
